#include "config.h"
#include "iniparser.h"

#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define DEFAULT_LOCAL_IP "127.0.0.1"
#define DEFAULT_REMOTE_IP "127.0.0.1"
#define DEFAULT_LOCAL_PORT 8000
#define DEFAULT_REMOTE_PORT 8000
#define DEFAULT_MREQ_IP "192.168.1.255"
#define DEFAULT_LOCAL_MAC "00:00:00:00:00"
#define DEFAULT_REMOTE_MAC "00:00:00:00:00"
#define DEFAULT_LOCAL_DEV "defalut"
#define DEFAULT_REMOTE_DEV "default"


const char* key_local_ip = "local:ip"; 
const char* key_local_mac = "local:mac"; 
const char* key_local_dev = "local:dev"; 
const char* key_local_port = "local:port"; 
const char* key_send_limit = "local:send-limit"; 


const char* key_remote_ip = "remote:ip"; 
const char* key_remote_mac = "remote:mac"; 
const char* key_remote_dev = "remote:dev"; 
const char* key_remote_port = "remote:port"; 
const char* key_mreq_ip = "mreq:ip";
const char* key_plugin_parameter = "local:plugin";

#define GET_VALUE(dst, key, def) read_string_value(dst, key, def); 
#define LOCAL_IP(dst,len) read_string_value(dst, len, key_local_ip, DEFAULT_LOCAL_IP); 
#define LOCAL_MAC(dst,len) read_string_value(dst, len, key_local_mac, DEFAULT_LOCAL_MAC); 
#define LOCAL_DEV(dst,len) read_string_value(dst, len, key_local_dev, DEFAULT_LOCAL_DEV); 
#define LOCAL_PORT read_int64_value(key_local_port, DEFAULT_LOCAL_PORT); 
#define LOCAL_SEND_LIMIT read_int64_value(key_send_limit, 0); 

#define REMOTE_IP(dst,len) read_string_value(dst, len, key_remote_ip, DEFAULT_REMOTE_IP); 
#define REMOTE_MAC(dst,len) read_string_value(dst, len, key_remote_mac, DEFAULT_REMOTE_MAC); 
#define REMOTE_DEV(dst,len) read_string_value(dst, len, key_remote_dev, DEFAULT_REMOTE_DEV); 
#define REMOTE_PORT read_int64_value(key_remote_port, DEFAULT_REMOTE_PORT); 
#define MREQ_IP(dst, len) read_string_value(dst, len, key_mreq_ip, DEFAULT_MREQ_IP); 
#define PLUGIN_PARAMETER(dst,len) read_string_value(dst, len, key_plugin_parameter, "");

static char* udp_type_string(uint16_t type) {
	switch(type) {
		case 1:
			return "unicast";
		case 2:
			return "multicast";
		case 3:
			return "broadcast";
		default:
			return "unicast";
	}
}

static dictionary* dict = NULL;
int load_file(const char* fn)
{
	dict = iniparser_load(fn);
	return (dict == NULL) ? -1 : 0;
}

static int read_string_value(char* dst, uint16_t size, const char* key, const char* def)
{
	if (dict == NULL) {
		return 0;
	}
	const char* value  = iniparser_getstring(dict, key, def);
	uint16_t len;;
	if (value) {
		len = strlen(value);
		if (len > size) {
			len = size;
		}
		memset(dst, 0, size);
		strncpy(dst, value, len);
	}
	return 0;
}

static int64_t read_int64_value(const char* key, int64_t def)
{
	return iniparser_getint64(dict, key, def);
}

uint8_t a2x(const char c)
{
	switch(c) {
		case '0'...'9':
			return (uint8_t)atoi(&c);
		case 'a'...'f':
			return 0xa + (c-'a');
		case 'A'...'F':
			return 0xa + (c-'A');
		default:
			return 0xFF;
	}
}

void parse_input_parameter(p_main_flow mflow)
{
	char buf[32] = {0};
	uint32_t k = 0;
	uint32_t uint[6];

	if (dict == NULL) {
		return;
	}

	LOCAL_IP(buf, 30)
	memcpy(mflow->m_flow_state.sstate.local_ip, buf, 16);
	REMOTE_IP(buf, 30)
	memcpy(mflow->m_flow_state.sstate.remote_ip, buf, 16);
	mflow->m_flow_state.sstate.local_port = LOCAL_PORT;
	mflow->m_flow_state.sstate.remote_port = REMOTE_PORT;
	mflow->m_flow_state.send_limit = LOCAL_SEND_LIMIT;

	MREQ_IP(buf, 30)
	memcpy(mflow->m_flow_state.sstate.mreq_ip, buf, 16);

	switch (read_int64_value("local:type", 1)) {
		case 1:
			mflow->m_socket_io.udp_type = SOCKET_IO_TYPE_UDP_S;
			break;
		case 2:
			mflow->m_socket_io.udp_type = SOCKET_IO_TYPE_UDP_M;
			break;
		case 3:
			mflow->m_socket_io.udp_type = SOCKET_IO_TYPE_UDP_B;
			break;
		default:
			mflow->m_socket_io.udp_type = SOCKET_IO_TYPE_UDP_S;
	}
	switch (read_int64_value("local:sockopt", 1)) {
		case 1:
			mflow->m_socket_io.sopt = sockopt_none;
			break;
		case 2:
			mflow->m_socket_io.sopt = sockopt_rcvtimeo;
			break;
		default:
			mflow->m_socket_io.sopt = sockopt_none;
	}
	k = read_int64_value("local:socket-type", (int)socket_none);
	if (k >= 0 && k < (int)socket_none) mflow->m_socket_io.s_type = (socket_type)k;
	else mflow->m_socket_io.s_type = socket_none;

	k = read_int64_value("local:rcvtimo", 0);
	mflow->m_socket_io.recv_timeout.tv_sec = k/1000;
	k -= mflow->m_socket_io.recv_timeout.tv_sec*1000;
	mflow->m_socket_io.recv_timeout.tv_usec = k*1000;

	k = read_int64_value("local:mode", 1);
	if (k > 4 || k < 1)
		k = 1;
	mflow->m_socket_io.flow_type = k;

	k = read_int64_value("local:ddirect", 0);
	if (mflow->m_socket_io.flow_type == 1) {
		if (k != 3) k = 0;
	} else {
		if (k !=2 && k != 1) k = 2;
	}
	mflow->m_flow_data_direct = k;
	if (mflow->m_socket_io.udp_type != SOCKET_IO_TYPE_UDP_S) {
		mflow->m_flow_data_direct = 0;
	}

	k = read_int64_value("local:dsize", 1024);
	mflow->m_data_size = (k < 2 ? 2 : k);

	LOCAL_DEV(buf, 30);
	strncpy(mflow->m_socket_io.if_name, buf, IFNAMSIZ);

	k = 0;
	REMOTE_MAC(buf, 30);
	sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
			&(uint[0]),
			&(uint[1]),
			&(uint[2]),
			&(uint[3]),
			&(uint[4]),
			&(uint[5]));
	for (int i = 0; i < 6; i++)
		mflow->m_socket_io.r_remote_addr.sll_addr[i] = uint[i] & 0xFF;

	PLUGIN_PARAMETER(mflow->plugin_parameter, 256);
}

void print_main_flow_input(p_main_flow mflow)
{
	int n = 50;
#define PRINT_SPLIT(x) for (int i = 0;i < n; i++) printf("%s", x);printf("\n");

	PRINT_SPLIT("*");
	printf("local-ip:%s\n", mflow->m_flow_state.sstate.local_ip);
	printf("local-port:%d\n", mflow->m_flow_state.sstate.local_port);
	printf("remote-ip:%s\n", mflow->m_flow_state.sstate.remote_ip);
	printf("remote-port:%d\n", mflow->m_flow_state.sstate.remote_port);
	printf("mreq-ip:%s\n", mflow->m_flow_state.sstate.mreq_ip);
	printf("udp-type:%s\n", udp_type_string(mflow->m_socket_io.udp_type));
	printf("sockopt:%s\n", (mflow->m_socket_io.sopt == sockopt_none)?"none":"rcvtimo");
	printf("rcvtimo:%ld ms\n", mflow->m_socket_io.recv_timeout.tv_sec*1000+mflow->m_socket_io.recv_timeout.tv_usec/1000);
	printf("mode:%s\n", (mflow->m_socket_io.flow_type % 2)?"client":"server");
	switch (mflow->m_flow_data_direct)
	{
		case 0:
			printf("direct:none\n");
			break;
		case 1:
			printf("direct:back\n");
			break;
		case 2:
			printf("direct:drop\n");
			break;
		case 3:
			printf("direct:loop\n");
			break;
		default:
			printf("direct:error");
	}
	printf("size:%d\n", (mflow->m_data_size));
	PRINT_SPLIT("*");
}

void init_main_flow_config(p_main_flow mflow)
{
	memcpy(mflow->m_flow_state.sstate.local_ip, DEFAULT_LOCAL_IP, sizeof(DEFAULT_LOCAL_IP));
	memcpy(mflow->m_flow_state.sstate.remote_ip, DEFAULT_REMOTE_IP, sizeof(DEFAULT_REMOTE_IP));
	mflow->m_flow_state.sstate.local_port = DEFAULT_LOCAL_PORT;
	mflow->m_flow_state.sstate.remote_port = DEFAULT_REMOTE_PORT;

	memcpy(mflow->m_flow_state.sstate.mreq_ip, DEFAULT_MREQ_IP, sizeof(DEFAULT_MREQ_IP));

	mflow->m_socket_io.udp_type = SOCKET_IO_TYPE_UDP_S;
	mflow->m_socket_io.sopt = sockopt_none;
	mflow->m_socket_io.recv_timeout.tv_sec = 1;
	mflow->m_socket_io.recv_timeout.tv_usec = 0;
	mflow->m_socket_io.s_type = socket_none;

	mflow->m_socket_io.flow_type = 1;

	mflow->m_flow_data_direct = 0;

	mflow->m_data_size = 1024;
}
